package com.fadadianqi.search;

import com.fadadianqi.commons.JSONProvider;
import com.yeqiangwei.commons.io.FileHelper;
import com.yeqiangwei.commons.util.StringHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;

public abstract class AbstractIndexService {

    private static final Log log = LogFactory.getLog(AbstractIndexService.class);

    private static Analyzer analyzer;

    protected static final String ADD_TIME = "addTime";

    public AbstractIndexService() {
        analyzer = AnalyzerFactory.getInstance();
    }

    protected Analyzer getAnalyzer() {
        return analyzer;
    }

    /**
     * 当前搜索正在使用的索引存放路径
     *
     * @return
     */
    protected abstract String getCurrentIndexPath();

    /**
     * 重新创建索引的临时路径
     *
     * @return
     */
    protected abstract String getNewIndexPath();


    public void removeIndex(String id) throws Exception {
        IndexWriter writer = SearchUtils.getIndexWriter(getCurrentIndexPath());
        writer.deleteDocuments(new Term("id", id));
        writer.optimize();
        writer.close();
    }

    protected abstract void build(IndexWriter writer, boolean rebuild) throws Exception;

    private void building() throws Exception {
        try {
            IndexWriter writer = SearchUtils.getIndexWriter(getCurrentIndexPath());
            build(writer, Boolean.FALSE);
        } catch (Exception e) {
            unlock();
            throw new Exception(e);
        }

    }

    private void rebuilding() throws Exception {
        try {
            String path = getNewIndexPath();
            IndexWriter writer = SearchUtils.getIndexWriter(path);
            build(writer, Boolean.TRUE);
            // 索引成功创建后需要将搜索服务索引目录切换到新目录
            changeIndexPath();
            log.info("Current index path: " + getCurrentIndexPath());
        } catch (Exception e) {
            unlock();
            throw new Exception(e);
        }
    }

    /**
     * 索引成功创建后需要将搜索服务索引目录切换到新目录
     */
    protected abstract void changeIndexPath();

    public void build() throws Exception {
        if (isRunning()) {
            log.warn("#build# is running...");
            return;
        }
        lock();
        log.info("#build# append: " + getCurrentIndexPath());
        FileHelper.createFolder(getCurrentIndexPath());
        building();
        unlock();
    }

    public void rebuild() throws Exception {
        if (isRunning()) {
            log.warn("#build# is running...");
            return;
        }
        rebuilding();
    }

    public void build(Object object) throws Exception {
        if (isRunning()) {
            log.warn("#build(" + object.toString() + ")# is already running...");
            return;
            //throw new Exception("#build(" + object.toString() + ")# is already running...");
        }
        lock();
        if (log.isInfoEnabled()) {
            log.info("#build(" + object.getClass().getCanonicalName() + ")# " + JSONProvider.toJSON(object));
        }
        String path = getCurrentIndexPath();
        log.info("#Current Index Path# " + path);
        IndexWriter writer;
        try {
            writer = SearchUtils.getIndexWriter(path);
            writer.addDocument(documentBuilder(object));
            writer.optimize();
            writer.close(true);
        } catch (Exception e) {
            unlock();
            throw new Exception(e.toString());
        }
        unlock();
    }

    protected abstract Document documentBuilder(Object object) throws Exception;

    public abstract boolean isRunning();

    protected abstract void lock();

    protected abstract void unlock();

    /**
     * 将文字转成带空格拼音和不带空格拼音的组合
     * 利于搜索的灵活性
     * 如："韦小宝" 转 "weixiaobao wei xiao bao"
     *
     * @param doc
     * @param key
     * @param str
     */
    protected String toPinyinIndexContent(String str) {
        StringBuilder tmp = new StringBuilder();
        tmp.append(StringHelper.toPinyin(str));
        tmp.append(" ");
        int len = str.length();
        for (int i = 0; i < len; i++) {
            char c = str.charAt(i);
            String pinyin = StringHelper.toPinyin(String.valueOf(c));
            tmp.append(pinyin);
            if (i != (len - 1)) {
                tmp.append(" ");
            }
        }
        return tmp.toString();
    }

}
